package xj.graph2d.template;

import java.util.Map;

import javax.swing.Icon;

import xj.graph2d.DrawShape;
import xj.graph2d.DrawShapeConstants;
import xj.graph2d.EllipseShape;
import xj.graph2d.GraphNodeBase;
import xj.graph2d.LineShape;
import xj.graph2d.RectangleShape;
import xj.graph2d.TextShape;
import xj.graph2d.shapes.BoxLabel;
import xj.graph2d.shapes.GraphEdgeShape;
import xj.graph2d.shapes.IconShape;
import xj.graph2d.shapes.RectangularShape;
import xj.graph2d.shapes.ShapeConstants;
import xj.graph2d.shapes.OrthogonalLineShape;
import xj.graph2d.shapes.PolyLineShape;
import xj.graph2d.shapes.uml.UMLUtil;
import xj.graph2d.template.uml.UMLActorModelListener;
import xj.graph2d.template.uml.UMLSystemBoundaryModelListener;
import xj.graph2d.template.uml.UMLUseCaseModelListener;
import xj.model.uml.Actor;
import xj.model.uml.UMLAssociation;
import xj.model.uml.UMLSystemBoundary;
import xj.model.uml.UseCase;

public class UMLUseCaseDiagramTemplate extends UMLTemplate {

  // UseCase Diagram

  static String[][] useCaseNodeEdgeToolNames = {
    // TOP_SIDE
    { "Extension1-Popup" },

    // BOTTOM_SIDE 
    { "Extension2-Popup" },

    // LEFT_SIDE
    {  "Association1-Popup", "Dependency1-Popup", "Dependency2-Popup", }, 

    // RIGHT_SIDE
    {  "Association1-Popup", "Dependency3-Popup", "Dependency4-Popup", }, 
  };

  static String[][] actorNodeEdgeToolNames = {
    // TOP_SIDE
    { "Extension1-Popup" },

    // BOTTOM_SIDE 
    { "Extension2-Popup" },

    // LEFT_SIDE
    {  "Association1-Popup", }, 

    // RIGHT_SIDE
    {  "Association1-Popup", }, 
  };

  static String[][] useCaseDiagramGapToolNames = {
    { "UseCase", "Actor1", "Actor2", "Boundary", },
  };

  static String[] dependencyEdgeShapeNames = {
    "Dependency-Shape1", 
    "Dependency-Shape2", 
    "Dependency-Shape3", 
    "Dependency-Shape4", 
    "Dependency-Shape5", 
  };

  static String[] assocEdgeShapeNames = {
    "Association-Shape1", 
    "Association-Shape2", 
    "Association-Shape3", 
    "Association-Shape4",
    "Association-Shape5",
  };

  static String[] extensionEdgeShapeNames = {
    "Extension-Shape1", 
    "Extension-Shape2", 
    "Extension-Shape3", 
    "Extension-Shape4", 
    "Extension-Shape5", 
  };

  public UMLUseCaseDiagramTemplate() {
  }

  @Override
  public void initTools() {
    addNodeToolNames(name + ".UseCase", useCaseNodeEdgeToolNames);
    addNodeToolNames(name + ".Actor1", actorNodeEdgeToolNames);
    addNodeToolNames(name + ".Actor2", actorNodeEdgeToolNames);

    addEdgeToolNames(name + ".Dependency", dependencyEdgeShapeNames);
    addEdgeToolNames(name + ".Association", assocEdgeShapeNames);
    addEdgeToolNames(name + ".Extension", extensionEdgeShapeNames);
  }

  @Override
  public String[][] getGapToolNames() { 
    return useCaseDiagramGapToolNames;
  }

  @Override
  public void makeTemplate(Map iconMap) {
    // actor
    addActorTemplate("Actor1", null, false);
    addActorTemplate("Actor2", null, true);
    // addActorTemplate("Actor2", iconMap);

    // use case
    addUseCaseTemplate("UseCase");

    // dependency
    LineShape line1 = new LineShape(0, 20, 50, 20);
    GraphEdgeShape line = new GraphEdgeShape(0, 20, 50, 20);
    addDependencyTemplate("Dependency", line, line1,
			  UMLAssociation.AssociationType.UseCaseDependency,
			  USE_CASE_DEPENDENCY_COLOR);

    // association
    addAssociationTemplate("Association", null, null,
			   USE_CASE_ASSOCIATION_COLOR);

    // extension
    line1 = new LineShape(0, 20, 50, 20);
    line = new GraphEdgeShape(0, 20, 50, 20);
    addGeneralizationTemplate("Extension", line, line1, 36, 24,  
			      false, EXTENSION_COLOR);

    addSystemBoundaryTemplate("Boundary");

    // notes
    addNotesTemplate("Notes1", true);
    addNotesTemplate("Notes2", false);

    // link
    addNotesLinkTemplate("Link", new LineShape(0, 20, 50, 20));

    makeNodeEdgePopupTemplates();
    makeEdgeShapeTemplates();
  }

  protected void makeNodeEdgePopupTemplates() { 

    // Dependency

    LineShape line1 = new LineShape(0, 10, 40, 10, true);
    addDependencyTemplate("Dependency1-Popup", "Dependency", line1, 25, 10, 
			   UMLAssociation.AssociationType.UseCaseDependency, true,
			  USE_CASE_DEPENDENCY_COLOR, TemplateToolButton.POPUP_BUTTON);
    line1 = new LineShape(40, 10, 0, 10, true);
    addDependencyTemplate("Dependency2-Popup", "Dependency", line1, 25, 10,
			  UMLAssociation.AssociationType.UseCaseDependency, false,
			  USE_CASE_DEPENDENCY_COLOR, TemplateToolButton.POPUP_BUTTON);

    line1 = new LineShape(0, 10, 40, 10, true);
    addDependencyTemplate("Dependency3-Popup", "Dependency", line1, 25, 10,
			  UMLAssociation.AssociationType.UseCaseDependency, false,
			  USE_CASE_DEPENDENCY_COLOR, TemplateToolButton.POPUP_BUTTON);
    line1 = new LineShape(40, 10, 0, 10, true);
    addDependencyTemplate("Dependency4-Popup", "Dependency", line1, 25, 10,
			  UMLAssociation.AssociationType.UseCaseDependency, true,
			  USE_CASE_DEPENDENCY_COLOR, TemplateToolButton.POPUP_BUTTON);

    // Association 

    line1 = new LineShape(0, 10, 40, 10, true);
    addAssociationTemplate("Association1-Popup", "Association", line1, 25, 10, 
			   null, null, false, 
			   USE_CASE_ASSOCIATION_COLOR, TemplateToolButton.POPUP_BUTTON);

    // Extension 

    line1 = new LineShape(10, 40, 10, 0);
    addGeneralizationTemplate("Extension1-Popup", "Extension", line1, 16, 20, 
			      false, false,EXTENSION_COLOR, TemplateToolButton.POPUP_BUTTON);
    line1 = new LineShape(10, 40, 10, 0);
    addGeneralizationTemplate("Extension2-Popup", "Extension", line1, 16, 20, 
			      false, true, EXTENSION_COLOR, TemplateToolButton.POPUP_BUTTON);  

  }

  protected void makeEdgeShapeTemplates() { 
    // association edge shape template 

    LineShape line = new LineShape(0, 10, 100, 10);
    addAssociationShapeTemplate("Association-Shape1", line, USE_CASE_ASSOCIATION_COLOR, 25, 10);
    
    PolyLineShape pline = new PolyLineShape(0, 20);
    pline.addPoint(30, 40);
    pline.addPoint(70, 0);
    pline.addPoint(100, 20);
    addAssociationShapeTemplate("Association-Shape2", pline, USE_CASE_ASSOCIATION_COLOR, 25, 10);

    OrthogonalLineShape oline = new OrthogonalLineShape(0, 0);
    oline.addPoint(40, 40);
    oline.addPoint(100, 0);
    oline.calculateBounds();
    addAssociationShapeTemplate("Association-Shape3", oline, USE_CASE_ASSOCIATION_COLOR, 25, 10);

    oline = new OrthogonalLineShape(0, 40);
    oline.addPoint(100, 5);
    oline.calculateBounds();
    addAssociationShapeTemplate("Association-Shape4", oline, USE_CASE_ASSOCIATION_COLOR, 25, 10);

    oline = new OrthogonalLineShape(false, 0, 40);
    oline.addPoint(50, 20);
    oline.addPoint(100, 0);
    oline.calculateBounds();
    addAssociationShapeTemplate("Association-Shape5", oline, USE_CASE_ASSOCIATION_COLOR, 25, 10);

    // extension edge shape template 

    line = new LineShape(0, 10, 100, 10);
    addGeneralizationShapeTemplate("Extension-Shape1", line, false, EXTENSION_COLOR, 25, 10);
    
    pline = new PolyLineShape(0, 20);
    pline.addPoint(30, 40);
    pline.addPoint(70, 0);
    pline.addPoint(100, 20);
    addGeneralizationShapeTemplate("Extension-Shape2", pline, false, EXTENSION_COLOR, 25, 10);

    oline = new OrthogonalLineShape(0, 0);
    oline.addPoint(40, 40);
    oline.addPoint(100, 0);
    oline.calculateBounds();
    addGeneralizationShapeTemplate("Extension-Shape3", oline, false, EXTENSION_COLOR, 25, 10);

    oline = new OrthogonalLineShape(0, 40);
    oline.addPoint(100, 5);
    oline.calculateBounds();
    addGeneralizationShapeTemplate("Extension-Shape4", oline, false, EXTENSION_COLOR, 25, 10);

    oline = new OrthogonalLineShape(false, 0, 40);
    oline.addPoint(50, 20);
    oline.addPoint(100, 0);
    oline.calculateBounds();
    addGeneralizationShapeTemplate("Extension-Shape5", oline, false, EXTENSION_COLOR, 25, 10);

    // dependency edge shape template 

    line = new LineShape(0, 10, 100, 10);
    addDependencyShapeTemplate("Dependency-Shape1", line, USE_CASE_DEPENDENCY_COLOR, 25, 10);
    
    pline = new PolyLineShape(0, 20);
    pline.addPoint(30, 40);
    pline.addPoint(70, 0);
    pline.addPoint(100, 20);
    addDependencyShapeTemplate("Dependency-Shape2", pline, USE_CASE_DEPENDENCY_COLOR, 25, 10);

    oline = new OrthogonalLineShape(0, 0);
    oline.addPoint(40, 40);
    oline.addPoint(100, 0);
    oline.calculateBounds();
    addDependencyShapeTemplate("Dependency-Shape3", oline, USE_CASE_DEPENDENCY_COLOR, 25, 10);

    oline = new OrthogonalLineShape(0, 40);
    oline.addPoint(100, 5);
    oline.calculateBounds();
    addDependencyShapeTemplate("Dependency-Shape4", oline, USE_CASE_DEPENDENCY_COLOR, 25, 10);

    oline = new OrthogonalLineShape(false, 0, 40);
    oline.addPoint(50, 20);
    oline.addPoint(100, 0);
    oline.calculateBounds();
    addDependencyShapeTemplate("Dependency-Shape5", oline, USE_CASE_DEPENDENCY_COLOR, 25, 10);
  }

  protected void addActorTemplate(String tempName, Map iconMap, boolean terminal) {
    DrawShape iconShape;
    GraphNodeBase shape;
    int iconWidth = 36, iconHeight = 30;

    String keyFG, keyBG, keyFont, keyColor; 
    if (terminal) {
      keyFG = ACTOR2_FG;
      keyBG = ACTOR2_BG;
      keyFont = ACTOR2_FONT;
      keyColor = ACTOR2_COLOR;      
    } else { 
      keyFG = ACTOR1_FG;
      keyBG = ACTOR1_BG;
      keyFont = ACTOR1_FONT;
      keyColor = ACTOR1_COLOR;      
    }
    
    if (iconMap != null) {
      Icon actorIcon = (Icon) iconMap.get(ACTOR_ICON);
      iconShape = new IconShape(actorIcon);
      iconShape.showBorder(false);
      iconShape.setAllowRotation(false);
      shape = new IconShape(actorIcon);
      shape.showBorder(false);
      shape.setAllowRotation(false);
    } else {
      int stype;
      int width, height, lwidth;
      if (terminal) {
	stype = ShapeConstants.TERMINAL_SHAPE;
	width = 50;
	height = 40;
	lwidth = 2;
	iconHeight = 24; 
      } else {
	stype = ShapeConstants.ACTOR_SHAPE;
	width = 30;
	height = 50;
	lwidth = 3;
      }

      iconShape = new RectangularShape(stype, ShapeConstants.NORTH, 0, 0, width, height);
      setNodeAttr(iconShape);
      setLineWidth(iconShape, 3);
      setPenColor(iconShape, keyFG);
      shape = new RectangularShape(stype, ShapeConstants.NORTH, 0, 0, width, height);
      setNodeAttr(shape);
      setLineWidth(shape, lwidth);
      setPenColor(shape, keyFG);
    }

    // TextShape text = makeTitleText("Actor");
    // text.setDisplayName("Name");
    // shape.setLabel(DrawShape.ROLE_NODE_LABEL, text);

    TextShape stereotype = makeContentText(null, "stereotype", "\u00AB", "\u00BB", 
					   true, STEREOTYPE_FONT, STEREOTYPE_COLOR);
    stereotype.setDisplayName("Stereotypes");

    BoxLabel header;
    if (useIconInLabel() && iconMap != null) {
      BoxLabel label = makeTitleLabel("Actor", iconMap, keyFont, keyColor);
      header = UMLUtil.makeHeader(label, stereotype);
    } else {
      TextShape text = makeTitleText("Actor", keyFont, keyColor);
      text.setDisplayName("Name");
      header = UMLUtil.makeHeader(text, stereotype);
    }
    shape.setLabel(DrawShapeConstants.ROLE_NODE_LABEL, header);

    shape.setAcceptSubshape(false);
    shape.setScaleMode(DrawShapeConstants.SCALE_EXCLUDE_SUBSHAPE);

    shape.setModel(new Actor());
    shape.setModelListener(new UMLActorModelListener());

    add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, false, true));
  }

  protected void addUseCaseTemplate(String tempName) {
    addUseCaseTemplate(tempName, null);
  }

  protected void addUseCaseTemplate(String tempName, Map iconMap) {
    DrawShape iconShape = new EllipseShape(0, 0, 100, 70);
    setNodeAttr(iconShape);
    setNodeColor(iconShape, USE_CASE_FG, USE_CASE_BG);

    EllipseShape shape = new EllipseShape(0, 0, 100, 70);
    setNodeAttr(shape);
    setNodeColor(shape, USE_CASE_FG, USE_CASE_BG);

    // TextShape text = makeTitleText("UseCase");
    // text.setDisplayName("Name");
    // shape.setLabel(DrawShape.ROLE_NODE_LABEL, text);

    TextShape stereotype = makeContentText(null, "stereotype", "\u00AB", "\u00BB", 
					   true, STEREOTYPE_FONT, STEREOTYPE_COLOR);
    stereotype.setDisplayName("Stereotypes");

    BoxLabel header;
    if (useIconInLabel() && iconMap != null) {
      BoxLabel label = makeTitleLabel("Name", iconMap, USE_CASE_FONT,
				      USE_CASE_COLOR);
      header = UMLUtil.makeHeader(label, stereotype);
    } else {
      TextShape text = makeTitleText("Name", USE_CASE_FONT, USE_CASE_COLOR);
      text.setDisplayName("Name");
      header = UMLUtil.makeHeader(text, stereotype);
    }
    shape.setLabel(DrawShapeConstants.ROLE_NODE_LABEL, header);

    shape.setAcceptSubshape(false);
    shape.setScaleMode(DrawShapeConstants.SCALE_EXCLUDE_SUBSHAPE);

    shape.setModel(new UseCase());
    shape.setModelListener(new UMLUseCaseModelListener());

    add(new TemplateToolButton(tempName, shape, iconShape, 36, 30, false, true));
  }

  protected void addSystemBoundaryTemplate(String tempName) {
    RectangleShape shape = new RectangleShape(0, 0, 200, 160);
    setNodeAttr(shape);
    setLineWidth(shape, 2);
    setPenColor(shape, BOUNDARY_FG);
    setNodeBgColor(shape, BOUNDARY_BG);
    shape.setAcceptSubshape(true);
    shape.setLabelPosition(GraphNodeBase.LABEL_POSITION_ABOVE_TOP);
    shape.setScaleMode(DrawShapeConstants.SCALE_EXCLUDE_SUBSHAPE);
    //shape.setAllowLabelOutside(true);
    shape.setClipSubShapes(false);

    shape.setModel(new UMLSystemBoundary());
    shape.setModelListener(new UMLSystemBoundaryModelListener(this));

    add(new TemplateToolButton(tempName, shape, 36, 30, false, true));
  }

  // actor style
  public static final String ACTOR1_FG = "template.UMLUseCaseDiagram.Actor1.fg";
  public static final String ACTOR1_BG = "template.UMLUseCaseDiagram.Actor1.bg";
  public static final String ACTOR1_FONT = "template.UMLUseCaseDiagram.Actor1.font";
  public static final String ACTOR1_COLOR = "template.UMLUseCaseDiagram.Actor1.color";

  public static final String ACTOR2_FG = "template.UMLUseCaseDiagram.Actor2.fg";
  public static final String ACTOR2_BG = "template.UMLUseCaseDiagram.Actor2.bg";
  public static final String ACTOR2_FONT = "template.UMLUseCaseDiagram.Actor2.font";
  public static final String ACTOR2_COLOR = "template.UMLUseCaseDiagram.Actor2.color";

  public static final String ACTOR_ICON = "terminalIcon";

  // use case style
  public static final String USE_CASE_BG = "template.UMLUseCaseDiagram.UseCase.bg";
  public static final String USE_CASE_FG = "template.UMLUseCaseDiagram.UseCase.fg";
  public static final String USE_CASE_FONT = "template.UMLUseCaseDiagram.UseCase.font";
  public static final String USE_CASE_COLOR = "template.UMLUseCaseDiagram.UseCase.color";

  public static final String USE_CASE_DEPENDENCY_COLOR = "template.UMLUseCaseDiagram.Dependency.color";
  public static final String USE_CASE_ASSOCIATION_COLOR = "template.UMLUseCaseDiagram.Association.color";

  public static final String EXTENSION_COLOR = "template.UMLUseCaseDiagram.Extension.color";

  // boundary style
  public static final String BOUNDARY_FG = "template.UMLUseCaseDiagram.Boundary.fg";
  public static final String BOUNDARY_BG = "template.UMLUseCaseDiagram.Boundary.bg";
  public static final String BOUNDARY_FONT = "template.UMLUseCaseDiagram.Boundary.font";
  public static final String BOUNDARY_COLOR = "template.UMLUseCaseDiagram.Boundary.color";

}
